
package data;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *Parser for data files of RCPSPs.
 * <p>
 * The files format must be like those at adress : http://www.om-db.wi.tum.de/psplib/datasm.html<BR>
 * (in archives named j##(#).sm.zip)
 */
public class Data {
    
    private static final String CHARSET = "UTF-8";
    private static final Locale LOCALE = Locale.US;
    
    private Scanner scan;
    
    //Project global informations
    private int nbJobs;     //number of jobs (without supersource and supersink)
    private int horizon;    //durations' jobs sum
    private int nbRess;     //number of ressources
    private int relDate;    //release date
    private int dueDate;
    private int tardCost;   // Cost if the project ends after due date
    private int mpmTime;    // ???

    //Project specific informations
    private ArrayList<Job> jobs;    //List of jobs
    private ArrayList<Integer> availableRess;   //amount available of ressources before start 
    
    
    public Data(String pathFile){
        try {
            scan = new Scanner(new File(pathFile), CHARSET);
            scan.useLocale(LOCALE);
            
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Data.class.getName()).log(Level.SEVERE, null, ex);
            System.err.println("Could not open file : " + pathFile);
        }
        
        jobs = new ArrayList<>();
        availableRess = new ArrayList<>();
    }
    
    /**
     * Reads the data file.
     * 
     * Used to initialize datas.
     */
    public void readFile(){
        
        initGlobalInformations();
        initSpecInformations();
        
    }
    
    private void initGlobalInformations(){
        
            try{
                nbJobs = nextInt(3) - 2;
                horizon = nextInt();
                nbRess = nextInt();
                relDate = nextInt(5);
                dueDate = nextInt();
                tardCost = nextInt();
                mpmTime = nextInt();
                
                
            }catch(NoSuchElementException e){
                e.printStackTrace();
                System.exit(1);
            }
    }
    
    /**
     * Initializes the different jobs and the ressources available from data file.
     * 
     */
    private void initSpecInformations(){
        ArrayList<ArrayList<Integer>> precRelations = 
                                      new ArrayList<ArrayList<Integer>>();
        int nbSucc; //To fix position in file when loop iterating over succesors
        
        try{
            //saves temporarly precedence(successors) relations
            for (int job = 0; job < nbJobs+2; job++) {
                precRelations.add(new ArrayList<Integer>());
                
                nbSucc = nextInt(3);
                
                for (int succ = 0; succ < nbSucc; succ++) {
                    precRelations.get(job).add(nextInt());
                }
            }
        
            nextInt(nbRess);
            
            //Initializes all jobs (duration + ressources needed) without precedences(successors) relations
            for (int job = 0; job < nbJobs+2; job++) {
                jobs.add(new Job(nextInt(3)));
                
                for (int ress = 0; ress < nbRess; ress++) {
                    jobs.get(job).addRessource(nextInt());
                }
            }
            
            //Initializes precedences(successors) for jobs 
            for (int job = 0; job < nbJobs+2; job++) {
                for (int succ = 0; succ < precRelations.get(job).size(); succ++) {
                    jobs.get(job).addSuccessor(
                                    jobs.get(precRelations.get(job).get(succ)-1));
                }
            }
            
            nextInt(nbRess);
            
            //Initializes amounts of ressources
            for (int ress = 0; ress < nbRess; ress++) {
                availableRess.add(nextInt());
            }
        
        }catch(NoSuchElementException e){
            e.printStackTrace();
            System.exit(1);
        }
    }
    
    /**
     * gets the next int in scanner.
     * @return the next int in scanner
     * @throws NoSuchElementException if there isn't next int in file
     */
    private int nextInt() throws NoSuchElementException{
        while(scan.hasNext()){
            if (scan.hasNextInt()){
                return scan.nextInt();
            }else scan.next();
        }
        throw new NoSuchElementException("There isn't any next integer in file");
    }
    
    /**
     * gets the next ith int in scanner.
     * @param i the number of next integers -1 which have to be ommited
     * @return the ith next int in scanner
     * @throws NoSuchElementException if there isn't next ith int in file
     */
    private int nextInt(int i) throws NoSuchElementException{
        
        for (int j = 0; j < i-1; j++) {
            nextInt();
        }
        return nextInt();
    }
    
    /**
     * Returns the number of jobs of this RCPSP (without supersource and supersink).
     * @return the number of jobs of this RCPSP (without supersource and supersink). 
     */
    public int getNbJobs() {
        return nbJobs;
    }
    
    /**
     * Returns the sum of all jobs process times.
     * @return the sum of all jobs process times.
     */
    public int getHorizon() {
        return horizon;
    }
    
    /**
     * Returns the number of differents kinds of ressources.
     * @return the number of differents kinds of ressources. 
     */
    public int getNbRess() {
        return nbRess;
    }
    
    /**
     * Returns the release date of this RCPSP.
     * @return the release date of this RCPSP. 
     */
    public int getRelDate() {
        return relDate;
    }
    
    /**
     * Returns the due date of this RCPSP.
     * @return the due date of this RCPSP. 
     */
    public int getDueDate() {
        return dueDate;
    }
    
    /**
     * Returns the cost if the project ends after due date.
     * @return the cost if the project ends after due date. 
     */
    public int getTardCost() {
        return tardCost;
    }

    public int getMpmTime() {
        return mpmTime;
    }
    
    /**
     * Returns all jobs of this RCPSP.
     * @return all jobs of this RCPSP. 
     */
    public ArrayList<Job> getJobs() {
        return jobs;
    }
    
    /**
     * Returns the amount of each kind of ressources available before starting the resolution of this RCPSP.
     * @return the amount of each kind of ressources available before starting the resolution of this RCPSP. 
     */
    public ArrayList<Integer> getAvailableRess() {
        return availableRess;
    }
    
    
    
    
    public static void main(String[] args){
        String path = System.getProperty("user.dir")+"\\DATA\\"; //mettre \\DATA\\ à la place de //DATA// sous windows
        File test = new File(path);
        test.mkdirs();
        
        Data dat = new Data(path + "j3047_10.sm");
        dat.readFile();
    }
}
